/**
 * 游戏手柄控制器类 - 单例模式
 * 管理游戏手柄连接、事件处理、模式切换和组合键功能
 * @class GamepadController
 * @singleton
 */
import React from "react";
import ReactDOM from "react-dom/client";
import {configService} from "./config";
import Gamepad2touch from "./eventAdapter";
import Pointer from "../components/Pointer";
import Configurator from "../components/Configurator";
import Guide from "../components/Guide";

import {
  MODE_GAMEPAD,
  MODE_VIRTUAL_POINTER,
  MODE_EDIT_CONFIG,
  MODE_GUIDE,
  STATE_INITIALIZED,
  STATE_RUNNING,
  STATE_DISCONNECTED,
  STATE_STOPPED,
  BUTTON_BACK,
  BUTTON_A,
  BUTTON_B,
  BUTTON_START,
  BUTTON_X,
} from "./constants";

export default class GamepadController {
  static instance = null;

  /**
   * 创建游戏手柄控制器实例
   * @constructor
   * @throws {Error} 如果尝试创建多个实例则抛出错误
   */
  constructor(parentContainer = null) {
    if (GamepadController.instance) {
      throw new Error(
        "Use GamepadController.getInstance() to get the single instance."
      );
    }
    GamepadController.instance = this;

    // 配置与状态
    this.config = { buttons: [] };
    this.configId = "";
    this.state = STATE_INITIALIZED;
    this.mode = MODE_GAMEPAD; // 初始化为游戏手柄模式
  
    this.g2t = new Gamepad2touch(); // Gamepad2touch实例

    // 事件系统
    this.eventSubscriptions = {}; // 事件订阅存储
    this.modeEventHandlers = {}; // 按模式存储的事件处理器 { mode: eventHandler }
    this.currentEventHandler = null; // 当前激活的事件处理器

    // 组合键系统
    this.functionButtons = {}; // 组合键配置
    this.buttonStates = {}; // 按钮状态跟踪 { buttonIndex: { pressed: boolean, startTime: number } }
    this.combinationTimers = {}; // 组合键定时器 { combinationId: timeoutId }

    // Touch事件处理
    this.touchEventHandlers = new Map();

    // 组件管理
    this.pointerRoot = null; // 虚拟指针React根实例
    this.pointerContainer = null; // 虚拟指针DOM容器
    this.configuratorRoot = null; // 配置器React根实例
    this.configuratorContainer = null; // 配置器DOM容器
    this.guideRoot = null; // 指引组件React根实例
    this.guideContainer = null; // 指引组件DOM容器
    this.isSupportedGamepad = false; // 是否支持的Xbox手柄

    // 尺寸适配
    this.parentContainer = parentContainer || document.body; // 默认父容器

    import("../joypad/index.js").then(() => {
      this.start();
    });
  }

  /**
   * 处理指引组件的渲染与清理
   * @param {number} mode - 当前模式
   */
  handleGuideComponent(mode) {
    this.renderComponent(
      mode,
      MODE_GUIDE,
      Guide,
      "guideContainer",
      "guideRoot"
    );
  }

  /**
   * 获取单例实例
   * @returns {GamepadController} 控制器实例
   */
  static getInstance(parentContainer = null) {
    if (!GamepadController.instance) {
      GamepadController.instance = new GamepadController(parentContainer);
    }
    return GamepadController.instance;
  }

  /**
   * 启动控制器并初始化
   */
  start() {
    if (this.state === STATE_RUNNING) return;

    joypad.set({ axisMovementThreshold: 0.001 });
    this.setupEventListeners();
    this.registerFunctionCombinations();

    // 设置初始鼠标事件状态
    if (this.parentContainer) {
      this.parentContainer.style.pointerEvents = this.mode === MODE_GAMEPAD ? 'none' : 'auto';
    }

    this.state = STATE_RUNNING;
  }

  /**
   * 设置事件监听器
   */
  setupEventListeners() {
    // 注册事件监听器
    this.eventSubscriptions.connect = joypad.on(
      "connect",
      this.handleGamepadConnect
    );
    this.eventSubscriptions.buttonPress = joypad.on(
      "button_press",
      this.handleGamepadButtonPress
    );
    this.eventSubscriptions.buttonRelease = joypad.on(
      "button_release",
      this.handleGamepadButtonRelease
    );
    this.eventSubscriptions.axisMove = joypad.on(
      "axis_move",
      this.handleGamepadAxisMove
    );
    this.eventSubscriptions.disconnect = joypad.on(
      "disconnect",
      this.handleGamepadDisconnect
    );
  }

  /**
   * 注册所有功能组合键
   */
  registerFunctionCombinations() {
    // 注册虚拟鼠标组合键
    this.registerVirtualMouseCombination();
    // 注册配置模式组合键
    this.registerConfiguratorCombination();
    // 注册返回游戏手柄模式组合键
    this.registerReturnGamepadCombination();
    // 注册显示指引组件组合键
    this.registerShowGuideCombination();
  }

  /**
   * 切换操作模式
   * @param {number} mode - 新模式
   * @param {Function} eventHandler - 模式对应的事件处理器
   * @param {boolean} saveToHistory - 是否保存当前模式到历史记录
   */
  switchMode = (mode, eventHandler, saveToHistory = true) => {
    if (
      ![
        MODE_GAMEPAD,
        MODE_VIRTUAL_POINTER,
        MODE_EDIT_CONFIG,
        MODE_GUIDE,
      ].includes(mode)
    ) {
      throw new Error(
        `Invalid mode: ${mode}. Must be one of ${[
          MODE_GAMEPAD,
          MODE_VIRTUAL_POINTER,
          MODE_EDIT_CONFIG,
        ]}`
      );
    }

    // 处理鼠标事件禁用/启用
    if (this.parentContainer) {
      this.parentContainer.style.pointerEvents = mode === MODE_GAMEPAD ? 'none' : 'auto';
    }

    // 如果已是目标模式则不切换
    if (this.mode === mode) {
      return;
    }
    
    this.mode = mode;
    // 更新事件处理器
    if (eventHandler) {
      this.modeEventHandlers[mode] = eventHandler;
    }
    this.currentEventHandler = this.modeEventHandlers[mode] || null;

    // 处理组件渲染
    this.handlePointerComponent(mode);
    this.handleConfiguratorComponent(mode);
    this.handleGuideComponent(mode);
  };

  /**
   * 通用组件渲染与清理方法
   * @param {number} mode - 当前模式
   * @param {number} targetMode - 目标激活模式
   * @param {string} componentPath - 组件路径
   * @param {string} containerProp - 容器属性名
   * @param {string} rootProp - 根实例属性名
   */
  /**
   * 通用组件渲染与清理方法
   * @async
   * @param {number} mode - 当前模式
   * @param {number} targetMode - 目标激活模式
   * @param {string} componentPath - 组件路径
   * @param {string} containerProp - 容器属性名
   * @param {string} rootProp - 根实例属性名
   * @returns {Promise<void>} - Promise对象
   */
  async renderComponent(mode, targetMode, Component, containerProp, rootProp) {
    if (mode === targetMode) {
      try {
        // const { default: Component } = await import(componentPath);
        const container = document.createElement("div");
        this.parentContainer.appendChild(container);
        container.className = "w-full h-full";
        this[containerProp] = container;
        this[rootProp] = ReactDOM.createRoot(container);
        this[rootProp].render(
          React.createElement(Component, {
            triggerTouchEvent: this.triggerTouchEvent.bind(this),
            config: this.config,
            saveGameConfig: this.saveConfig.bind(this),
          })
        );
      } catch (error) {
        console.error(
          `[GamepadController] Failed to load component ${componentPath}:`,
          error
        );
        // 清理容器元素
        if (container && container.parentNode) {
          container.parentNode.removeChild(container);
        }
      }
    } else if (this[rootProp]) {
      this[rootProp].unmount();
      this[containerProp].remove();
      this[rootProp] = null;
      this[containerProp] = null;
    }
  }

  /**
   * 处理虚拟指针组件的渲染与清理
   * @param {number} mode - 当前模式
   */
  handlePointerComponent(mode) {
    this.renderComponent(
      mode,
      MODE_VIRTUAL_POINTER,
      Pointer,
      "pointerContainer",
      "pointerRoot"
    );
  }

  /**
   * 处理配置器组件的渲染与清理
   * @param {number} mode - 当前模式
   */
  handleConfiguratorComponent(mode) {
    this.renderComponent(
      mode,
      MODE_EDIT_CONFIG,
      Configurator,
      "configuratorContainer",
      "configuratorRoot"
    );
  }


  /**
   * 保存游戏配置到本地
   * @param {string} configId - 配置ID
   * @returns {Promise<Object>} 保存的配置对象
   */
  saveConfig = async (config) => {
    const configId = this.configId;
    if (!configId || typeof configId !== 'string') {
      throw new Error('Invalid configId: must be a non-empty string');
    }
    this.updateConfig(config);
    try {
      await configService.saveGameConfig(config, configId);
      console.debug(`Config saved successfully for configId: ${configId}`);
      return this.config;
    } catch (error) {
      console.error('Failed to save game config:', error);
      throw error;
    }
  }

  /**
   * 加载游戏配置
   * @param {string} configId - 配置ID
   * @returns {Promise<Object>} 配置对象
   */
  loadGameConfig = async (configId) => {
    if (!configId || typeof configId !== "string") {
      throw new Error("Invalid configId: must be a non-empty string");
    }

    try {
      let config = (await configService.getGameConfig(configId)) || {};
      config = this.updateConfig(config);
      this.configId = configId;
      this.g2t?.updateConfig(config);
      return config;
    } catch (error) {
      console.error("Failed to load game config:", error);
      throw error;
    }
  };

  /**
   * 更新配置
   * @param {Object} config - 新配置对象
   */
  updateConfig(config) {
    if (!config || typeof config !== "object") {
      throw new Error("Invalid config: must be an object");
    }
    
    // 合并配置
    this.config = { ...this.config, ...config };
    
    // 按屏幕尺寸比例调整按钮坐标
    if (this.config.buttons && this.config.resolution) {
      const { width: savedWidth, height: savedHeight } = this.config.resolution;
      const currentWidth = this.parentContainer.clientWidth;

      if (savedWidth > 0 && savedHeight > 0) {
        const scaleX = currentWidth / savedWidth;
        // const scaleY = currentHeight / savedHeight;
        
        this.config.buttons = this.config.buttons.map(button => ({
          ...button,
          x: button.x * scaleX,
          y: button.y * scaleX
        }));
      } else {
        console.warn("Invalid saved resolution, cannot scale buttons");
      }
    }
    
    return this.config;
  }

  /**
   * 处理游戏手柄连接事件
   * @param {Object} e - 事件对象
   */
  handleGamepadConnect = (e) => {
    const gamepadName = (e.gamepad.name || e.gamepad.id || "").toLowerCase();
    const isXbox =
      gamepadName.includes("xbox") || gamepadName.includes("microsoft");

    if (isXbox) {
      this.isSupportedGamepad = true;
      this.currentEventHandler?.({
        gamepad: e.gamepad,
        eventType: "connect",
      });
      console.debug("Xbox游戏手柄已连接");
    } else {
      this.isSupportedGamepad = false;
      this.showUnsupportedGamepadMessage();
      console.warn(`不支持的游戏手柄: ${e.gamepad.name}`);
    }
  };

  /**
   * 处理游戏手柄按钮按下事件
   * @param {Object} e - 事件对象
   */
  /**
   * 处理游戏手柄事件数据
   * @param {Object} e - 原始事件对象
   * @param {string} eventType - 事件类型(press/release/move)
   * @returns {Object} 处理后的事件数据
   */
  processGamepadEvent = (e, eventType) => {
    if (!e || !e.detail) {
      console.warn(
        `[GamepadController] Invalid event data for type: ${eventType}`
      );
      return null;
    }

    if (this.mode === MODE_GAMEPAD && this.g2t) {
      return this.g2t.eventAdapter(e.detail, eventType);
    }
    return { code: '200', detail: e.detail };
  };

  /**
   * 处理游戏手柄按钮按下事件
   * @param {Object} e - 事件对象
   */
  handleGamepadButtonPress = (e) => {
    const eventData = this.processGamepadEvent(e, "press");
    if (!eventData) return;

    this.currentEventHandler?.({
      ...eventData,
      eventType: "press",
    });

    if (this.mode === MODE_GAMEPAD && eventData.actions) {
      for (let i = 0; i < eventData.actions.length; i++) {
        const action = eventData.actions[i];
        const data = this.createTouchEvent(action);
        this.triggerTouchEvent("down", data);
      }
    }
    const { index } = e.detail;
    // 记录按钮按下状态和时间
    this.buttonStates[index] = { pressed: true, startTime: Date.now() };
    if (this.isSupportedGamepad) {
      this.checkCombinations();
    }
  };

  /**
   * 处理游戏手柄按钮释放事件
   * @param {Object} e - 事件对象
   */
  /**
   * 处理游戏手柄按钮释放事件
   * @param {Object} e - 事件对象
   */
  handleGamepadButtonRelease = (e) => {
    const eventData = this.processGamepadEvent(e, "release");
    if (!eventData) return;

    this.currentEventHandler?.({
      ...eventData,
      eventType: "release",
    });

    if (this.mode === MODE_GAMEPAD && eventData.actions) {
      for (let i = 0; i < eventData.actions.length; i++) {
        const action = eventData.actions[i];
        const data = this.createTouchEvent(action);
        this.triggerTouchEvent("up", data);
      }
    }

    const { index } = e.detail;
    // 清除按钮状态和相关定时器
    this.buttonStates[index] = { pressed: false, startTime: null };
    this.clearCombinationTimers();
  };

  /**
   * 处理游戏手柄轴移动事件
   * @param {Object} e - 事件对象
   */
  /**
   * 处理游戏手柄轴移动事件
   * @param {Object} e - 事件对象
   */
  handleGamepadAxisMove = (e) => {
    const eventData = this.processGamepadEvent(e, "move");
    if (eventData.code != 200) return console.warn("游戏手柄轴移动事件处理失败");

    this.currentEventHandler?.({
      ...eventData,
      eventType: "move",
    });
    if (this.mode === MODE_GAMEPAD) {
      for (let i = 0; i < eventData.actions.length; i++) {
        const action = eventData.actions[i];
        const data = this.createTouchEvent(action);
        this.triggerTouchEvent(action.type, data);
      }
    }
  };

  /**
   * 处理游戏手柄断开连接事件
   */
  handleGamepadDisconnect = () => {
    this.state = STATE_DISCONNECTED;
    this.isSupportedGamepad = false;
    this.clearCombinationTimers();
  };

  showUnsupportedGamepadMessage = () => {
    // 创建不支持手柄提示元素
    const messageEl = document.createElement("div");
    messageEl.className =
      "fixed top-4 left-1/2 transform -translate-x-1/2 bg-red-500 text-white px-4 py-2 rounded shadow-lg z-50";
    messageEl.textContent = "不支持的手柄类型，请使用Xbox控制器";
    document.body.appendChild(messageEl);

    // 5秒后自动移除提示
    setTimeout(() => {
      messageEl.remove();
    }, 5000);
  };

  /**
   * 注册模式事件处理器
   * @param {number} mode - 模式
   * @param {Function} handler - 事件处理函数
   */
  registerModeEventHandler(mode, handler) {
    if (
      ![MODE_GAMEPAD, MODE_VIRTUAL_POINTER, MODE_EDIT_CONFIG].includes(mode)
    ) {
      throw new Error(
        `Invalid mode: ${mode}. Must be one of ${[
          MODE_GAMEPAD,
          MODE_VIRTUAL_POINTER,
          MODE_EDIT_CONFIG,
        ]}`
      );
    }
    if (typeof handler !== "function") {
      throw new Error("Invalid handler: must be a function");
    }
    this.modeEventHandlers[mode] = handler;

    // 如果当前模式是该模式，立即更新当前事件处理器
    if (this.mode === mode) {
      this.currentEventHandler = handler;
    }
  }

  /**
   * 注册功能键组合
   * @param {string} combinationId - 组合标识
   * @param {number[]} buttons - 按钮索引数组
   * @param {Function} callback - 触发回调
   * @param {number} pressTime - 长按时间(ms)，默认3000ms
   */
  registerFunctionButton(
    combinationId,
    buttons = [],
    callback,
    pressTime = 3000
  ) {
    if (!combinationId || typeof combinationId !== "string") {
      throw new Error("Invalid combinationId: must be a non-empty string");
    }
    if (!Array.isArray(buttons) || buttons.some((b) => typeof b !== "number")) {
      throw new Error("Invalid buttons: must be an array of numbers");
    }
    if (typeof callback !== "function") {
      throw new Error("Invalid callback: must be a function");
    }
    if (typeof pressTime !== "number" || pressTime < 0) {
      throw new Error("Invalid pressTime: must be a non-negative number");
    }

    this.functionButtons[combinationId] = {
      buttons,
      callback,
      pressTime,
      triggered: false,
    };
  }

  /**
   * 注册虚拟鼠标模式组合键 (Back + A 长按)
   */
  registerVirtualMouseCombination() {
    const COMBINATION_DELAY = 100; // 长按3秒激活

    this.registerFunctionButton(
      "virtual_mouse_mode",
      [BUTTON_BACK, BUTTON_A],
      () => {
        this.switchMode(MODE_VIRTUAL_POINTER);

        console.debug("虚拟鼠标模式已激活");
      },
      COMBINATION_DELAY
    );
  }

  /**
   * 注册配置模式组合键 (Back + Start 长按)
   */
  registerConfiguratorCombination() {
    const COMBINATION_DELAY = 2000; // 长按3秒激活

    this.registerFunctionButton(
      "configurator_mode",
      [BUTTON_BACK, BUTTON_START],
      () => {
        this.switchMode(MODE_EDIT_CONFIG);

        console.debug("虚拟鼠标模式已激活");
      },
      COMBINATION_DELAY
    );
  }

  /**
   * 注册返回游戏手柄模式组合键 (Back + B 长按)
   */
  registerReturnGamepadCombination() {
    const COMBINATION_DELAY = 100; // 长按3秒激活

    this.registerFunctionButton(
      "return_gamepad_mode",
      [BUTTON_BACK, BUTTON_B],
      () => {
        this.switchMode(MODE_GAMEPAD);

        console.debug("已返回到游戏手柄模式");
      },
      COMBINATION_DELAY
    );
  }

  registerShowGuideCombination() {
    const COMBINATION_DELAY = 100; // 长按3秒激活

    this.registerFunctionButton(
      "show_guide",
      [BUTTON_BACK, BUTTON_X],
      () => {
        this.switchMode(MODE_GUIDE);
        console.debug("操作指引模式已激活");
      },
      COMBINATION_DELAY
    );
  }

  /**
   * 注册touch事件处理函数
   * @param {string} eventType - 事件类型 (如 'touchstart', 'touchmove', 'touchend')
   * @param {Function} handler - 事件处理函数
   */
  registerTouchEvent(eventType, handler) {
    if (typeof handler !== "function") {
      console.error(`Invalid touch event handler for type: ${eventType}`);
      return;
    }
    this.touchEventHandlers.set(eventType, handler);
  }

  /**
   * 触发touch事件
   * @param {string} eventType - 事件类型
   * @param {Object} eventData - 事件数据
   */
  triggerTouchEvent(eventType, eventData) {
    if (!this.isSupportedGamepad) return;

    const handler = this.touchEventHandlers.get(eventType);
    if (handler) {
      try {
        handler(eventData);
      } catch (error) {
        console.error(`Error triggering touch event ${eventType}:`, error);
      }
    }
  }

  /**
   * 创建触摸事件对象
   * @param {Object} action - 游戏手柄动作
   * @returns {Object} 触摸事件对象
   */
  createTouchEvent(action) {
    // 根据游戏手柄动作创建触摸事件对象
    return {
      nativeEvent: {
        changedTouches: [
          {
            clientX: action.x,
            clientY: action.y,
            identifier: action.id || 1,
          },
        ],
      },
    };
  }

  /**
   * 检查所有已注册的组合键
   */
  checkCombinations = () => {
    Object.entries(this.functionButtons).forEach(([combinationId, config]) => {
      this.checkSingleCombination(combinationId, config);
    });
  };

  /**
   * 检查单个组合键
   * @param {string} combinationId - 组合标识
   * @param {Object} config - 组合配置
   */
  checkSingleCombination = (combinationId, config) => {
    const { buttons, callback, pressTime, triggered } = config;

    // 检查组合中的所有按钮是否都已按下
    const allPressed = buttons.every(
      (buttonIndex) => this.buttonStates[buttonIndex]?.pressed
    );

    if (allPressed && !triggered) {
      this.handleCombinationActive(
        combinationId,
        config,
        buttons,
        callback,
        pressTime
      );
    } else if (!allPressed && triggered) {
      this.resetCombination(config);
    }
  };

  /**
   * 处理激活的组合键
   */
  handleCombinationActive = (
    combinationId,
    config,
    buttons,
    callback,
    pressTime
  ) => {
    // 检查是否所有按钮都达到了长按时间
    const allLongPressed = buttons.every(
      (buttonIndex) =>
        Date.now() - this.buttonStates[buttonIndex].startTime >= pressTime
    );

    if (allLongPressed) {
      callback();
      config.triggered = true; // 防止重复触发
      this.combinationTimers[combinationId] = setTimeout(() => {
        config.triggered = false;
      }, 1000); // 1秒内防止重复触发
    } else {
      // 设置长按检查定时器
      this.combinationTimers[combinationId] = setTimeout(() => {
        this.checkCombinations();
      }, 100);
    }
  };

  /**
   * 重置组合键状态
   */
  resetCombination = (config) => {
    config.triggered = false;
  };

  /**
   * 清除所有组合键定时器
   */
  clearCombinationTimers = () => {
    Object.values(this.combinationTimers).forEach((timerId) =>
      clearTimeout(timerId)
    );
    this.combinationTimers = {};
  };

  /**
   * 停止控制器并取消事件监听
   */
  stop() {
    if (this.state === STATE_STOPPED) return;

    // 取消所有事件订阅
    Object.values(this.eventSubscriptions).forEach((subscription) => {
      if (subscription && typeof subscription.unsubscribe === "function") {
        subscription.unsubscribe();
      }
    });

    this.clearCombinationTimers();
    this.state = STATE_STOPPED;
  }
}
